package omq.api;

import java.io.IOException;
import java.rmi.RemoteException;
import java.util.Calendar;

import javax.xml.rpc.ServiceException;

//import omq.soap.wsdl.client.*;
import com.onlinemq.mq.app.onlinemq_v1_api.*;

public class OMQConnectionSOAP extends OMQConnection 
{
	// -------------------------------------------------------------------------
	// these are the parrallel SOAP objects of the OMQ objects 
	// these are taken from the generated client of the WSDL
	// evey object from the WSDL will have a WO header (Wsdl Object(
	// -------------------------------------------------------------------------
	
	private final static String SoapVersion1URL = "http://mq.onlinemq.com/webservice_soap_v1/api";

	// request objects
	private OnlineMQRequestApiStruct WOinput;
	private OnlineMQStruct WOrequestOnlineMQStruct;

	// request sub-objects
	private HeaderStruct WOheader;
	private BodyTypeStruct[] WObody_types;
	private QueueManagerStruct[] WOqueue_managers;
	private BodyEncodingStruct[] WObody_encodings;
	private StatusStruct WOstatus;
	private QueueManagerStruct WOqueue_manager;
	private AuthenticationStruct WOauthentication;

	// response objects
	protected OnlineMQResponseApiStruct WOoutput;

	// constants
	private int OMQSoapVersion = 1;
	
	// -------------------------------------------------------------------------
	// These are SOAP related objects
	// -------------------------------------------------------------------------
	protected OnlineMQServiceLocator serviceLocator;	
	protected OnlineMQWebserviceSoapV1Port servicePort;

	/**
	 * constructor for OMQConnection type SOAP
	 * @param username
	 * @param password
	 * @param email
	 * @param connectionURL
	 * @param qmgr
	 * @throws ServiceException
	 */
	protected OMQConnectionSOAP(String username, String password, String connectionURL, OMQQueueManager qmgr) throws ServiceException 
	{
		
		super(username,password,connectionURL, new OMQConnectionTypeSOAP(),qmgr);
		
		serviceLocator = new OnlineMQServiceLocator();
		serviceLocator.setOnlineMQWebserviceSoapV1PortEndpointAddress(this.connectionURL);
		
		
		//TODO do we need this??
		serviceLocator.getEngine().setOption("sendMultiRefs", new Boolean(false));
		
		// request Soap Port
		servicePort = serviceLocator.getOnlineMQWebserviceSoapV1Port();
        
		WOrequestOnlineMQStruct = new OnlineMQStruct();
		WOinput = new OnlineMQRequestApiStruct();
	}

	protected OMQConnectionSOAP(String username, String password, OMQQueueManager qmgr) throws ServiceException 
	{
		this(username, password, SoapVersion1URL, qmgr);
	}

	
	/**
	 * constructor for OMQConnection type SOAP
	 * @param username
	 * @param password
	 * @param connectionURL
	 * @param qmgr
	 * @throws ServiceException
	 */
//	public OMQConnectionSOAP(String username, String password, OMQQueueManager qmgr) throws ServiceException 
//	{
//		this(username,password,null,qmgr);
//	}
	
	// -----------------------------------------------------------------------------------
	// START - each of the following methods creates the sub-objects of the WSDL request :
	// -----------------------------------------------------------------------------------
	

	/**
	 * init internal structure : HeaderStruct WOheader; 
	 * @param msg
	 */
	private void setWOHeader()
	{
		//  IMPORTNAT !!!! from http://onlinemq.com/support/index.php/Online_MQ_API:
		//	Because SOAP already has a specific enveloping for each action, the action field in the 
		//  canonical is ignored for the requests. It is returned in the response, but can be ignored. 
		action ="";
		if (WOheader == null)
		{
			WOheader = new HeaderStruct(action,Calendar.getInstance(),new Integer(OMQSoapVersion).toString());
		}
		else
		{
			WOheader.setVersion(new Integer(OMQSoapVersion).toString());
			WOheader.setCreated_at(Calendar.getInstance());
			WOheader.setAction(action);
		}
	}
	

	/**
	 * init internal structure : BodyTypeStruct[] WObody_types 
	 * @param msg
	 */
	private void setWObody_types()
	{
		WObody_types = new BodyTypeStruct[]{};
	}
	

	/**
	 * init internal structure : QueueManagerStruct[] WOqueue_managers 
	 * @param msg
	 */
	private void setWOqueue_managers()
	{
		WOqueue_managers = new QueueManagerStruct[]{new QueueManagerStruct()};
	}
	

	/**
	 * init internal structure : BodyEncodingStruct[] WObody_encodings 
	 * @param msg
	 */
	private void setWObody_encodings()
	{
		WObody_encodings = new BodyEncodingStruct[]{new BodyEncodingStruct()};
	}
	

	/**
	 * init internal structure : 
	 * @param msg
	 */
	private void setWOstatus()
	{
		WOstatus = new StatusStruct();
	}	
	
	/**
	 * init internal structure : AuthenticationStruct WOauthentication
	 * @param msg
	 */
	private void setWOauthentication()
	{
		if (WOauthentication == null)
		{
			WOauthentication = new AuthenticationStruct("",username,password);
		}
		else
		{
			WOauthentication.setLogin(username);
			WOauthentication.setPassword(password);
		}
	}

	/**
	 * init internal structure : QueueManagerStruct WOqueue_manager
	 * @param msg
	 */
	private void setWOqueue_manager(OMQMessage msg)
	{
		MessageStruct omqMsg;
		// message will be empty for any action other than send_message, which is fine, type will be base64 which is perfect for SOAP
		if (msg == null)
		{
			// when receiving, we always ask for the message in base64 encoding
			omqMsg = new MessageStruct("",new BodyEncodingStruct(0,new OMQBodyEncodingBase64().getBodyEncoding()),new BodyTypeStruct(0,new OMQBodyTypeOther().getBodyType()),"",0,"");
		}
		else
		{
			// when sending, we always use base64 encodinge 
			BodyEncodingStruct enc = new BodyEncodingStruct(0,new OMQBodyEncodingBase64().getBodyEncoding());
			BodyTypeStruct type = new BodyTypeStruct(0,msg.getMsgType().getBodyType());
			omqMsg = new MessageStruct(msg.getMsgBodyasBase64(),enc,type,"",0,msg.getSender());
		}
		QueueDefinitionStruct dummyQStruct = new QueueDefinitionStruct(0,"",0,0,omqMsg,queue.getName(),true,true,"",0);
		WOqueue_manager = new QueueManagerStruct("",true,0,qmgr.getQueuemanagerName(),dummyQStruct,null);
}
	// ------------------------------------------------------------------------------
	// END - each of the previous methods creates the sub-objects of the WSDL request
	// ------------------------------------------------------------------------------
	
	/**
	 * build SOAP request object using message=null (used for all actions besides send_message)
	 */
	private void buildRequest()
	{
		buildRequest(null);
	}
	
	/**
	 * build SOAP request object
	 * @param msg
	 */
	private void buildRequest(OMQMessage msg)
	{
		setWOHeader();
		WOrequestOnlineMQStruct.setHeader(WOheader);
		setWObody_types();
		WOrequestOnlineMQStruct.setBody_types(WObody_types);
		setWOqueue_managers();
		WOrequestOnlineMQStruct.setQueue_managers(WOqueue_managers);
		setWObody_encodings();
		WOrequestOnlineMQStruct.setBody_encodings(WObody_encodings);
		setWOstatus();
		WOrequestOnlineMQStruct.setStatus(WOstatus);
		setWOauthentication();
		WOrequestOnlineMQStruct.setAuthentication(WOauthentication);
		// msg can be null if we are not sending a message (action is not send_message)
		setWOqueue_manager(msg);
		WOrequestOnlineMQStruct.setQueue_manager(WOqueue_manager);
		
		//TODO init queue manager

		WOinput.setOnlinemq(WOrequestOnlineMQStruct);
	}
	

	
	/**
	 * calling SOAP check_connection method
	 * @param queue
	 */
	public int checkConnection(OMQQueue queue) throws RemoteException 
	{
		this.queue = queue;
		buildRequest();
		WOoutput = servicePort.checkConnection(WOinput);
		return getLastErrorCode();
	}

	/**
	 * calling SOAP send_connection method
	 * @param queue
	 * @param msg
	 */
	protected int sendMessage(OMQQueue queue, OMQMessage msg) throws RemoteException 
	{
		this.queue = queue;
		buildRequest(msg);
		WOoutput = servicePort.sendMessage(WOinput);
		return getLastErrorCode();
	}

	/**
	 * calling SOAP receive_connection method
	 * @param queue
	 */
	protected OMQMessage receiveMessage(OMQQueue queue) throws IOException 
	{
		this.queue = queue;
		buildRequest();
		WOoutput = servicePort.receiveMessage(WOinput);
		if (getLastErrorCode() == 0)
		{
			MessageStruct WSDLmsg = WOoutput.getOnlinemq().getQueue_manager().getQueue_definition().getMessage();
			// we always ask for messages in Base64, it's the recommended way to pass data
			return (new OMQMessage(WSDLmsg.getBody(),new OMQBodyType(WSDLmsg.getBody_type().getName()),WSDLmsg.getId(),WSDLmsg.getSender()));
		}
		else
		{
			return null;
		}
	}
	
	/**
	 * calling SOAP check_connection method
	 * @param queue
	 */
	protected OMQMessage peekMessage(OMQQueue queue) throws IOException 
	{
		this.queue = queue;
		buildRequest();
		WOoutput = servicePort.peekMessage(WOinput);
		if (getLastErrorCode() == 0)
		{
			MessageStruct WSDLmsg = WOoutput.getOnlinemq().getQueue_manager().getQueue_definition().getMessage();
			// we always ask for messages in Base64, it's the recommended way to pass data
			return (new OMQMessage(WSDLmsg.getBody(),new OMQBodyType(WSDLmsg.getBody_type().getName()),WSDLmsg.getId(),WSDLmsg.getSender()));
		}
		else
		{
			return null;
		}
	}
	
	/**
	 * calling SOAP empty_queue method
	 * @param queue
	 * @throws RemoteException 
	 */
	protected int emptyQueue(OMQQueue queue) throws RemoteException
	{
		this.queue = queue;
		buildRequest();
		WOoutput = servicePort.emptyQueueDefinition(WOinput);
		return getLastErrorCode();
	}
	
	/**
	 * calling SOAP get_queue_definitions method
	 * @param queue
	 * @throws RemoteException 
	 */
	protected OMQQueue getQueueDefinitions(OMQQueue queue) throws RemoteException
	{
		this.queue = queue;
		buildRequest();
		WOoutput = servicePort.showQueueDefinition(WOinput);
		if (getLastErrorCode() == 0)
		{
			QueueDefinitionStruct WSDLqueue = WOoutput.getOnlinemq().getQueue_manager().getQueue_definition();
			return (new OMQQueue(WSDLqueue.getName(),
					WSDLqueue.getDepth(),
					WSDLqueue.getDescription(),
					WSDLqueue.getId(),
					WSDLqueue.getMax_depth(),
					WSDLqueue.getReceive_enabled(),
					WSDLqueue.getSend_enabled(),
					WSDLqueue.getType(),
					WSDLqueue.getVisibility_timeout()));
		}
		else
		{
			return null;
		}
	}
	
	/**
	 * returns error code from the last performed action against OMQ, if no action was performed yet it'll return null
	 */
	public int getLastErrorCode()
	{
		String RC = WOoutput.getOnlinemq().getStatus().getError_code();
		return new Integer(RC).intValue();
	}
	
	/**
	 * returns error description from the last performed action against OMQ, if no action was performed yet it'll return null
	 */
	public String getLastErrorDescription()
	{
		String RC = WOoutput.getOnlinemq().getStatus().getError_description();
		return RC;
	}
	
	/**
	 * returns message-id from the last performed action against OMQ, if no message-id exist we return null
	 */
	protected String getLastMessageID() 
	{
		if (getLastErrorCode() ==0)
		{
			String lastMessageID = WOoutput.getOnlinemq().getQueue_manager().getQueue_definition().getMessage().getId();
			return lastMessageID;
		}
		else
		{
			return null;
		}
		
	}
}
